/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "rs_render_multi_process_manager.h"

#include <chrono>
#include <future>
#include <mutex>
#include <signal.h>
#include <sys/prctl.h>

#include "rs_composer_connection.h"
#include "rs_render_composer_agent.h"
#include "rs_render_composer_manager.h"
#include "screen_manager/screen_types.h"
#include "render_process/rs_render_process.h"
#include "rs_profiler.h"
#include "rs_render_service.h"
#include "rs_trace.h"

#include "pipeline/main_thread/rs_main_thread.h"
#include "platform/ohos/rs_render_service_connect_hub.h"
#include "transaction/rs_client_to_render_connection.h"

#undef LOG_TAG
#define LOG_TAG "RSMultiRenderProcessManager"

namespace OHOS {
namespace Rosen {
namespace {
constexpr int32_t MAX_RETRIES = 5;
}

RSMultiRenderProcessManager::RSMultiRenderProcessManager(RSRenderService& renderService) :
    RSRenderProcessManager(renderService) {}

int32_t ForkAndExec(GroupId groupId)
{
    pid_t pid = fork();
    RS_LOGW("Forked done %{public}d", pid);
    if (pid < 0) {
        RS_LOGE("fork failed, errorno:%{public}d, errormsg:%{public}s", errno, strerror(errno));
        return -1;
    }
    if (pid == 0) {
        RS_LOGW("dmulti_process Forked success self %{public}d, parent %{public}d", getpid(), getppid());
        prctl(PR_SET_PDEATHSIG, SIGKILL);
        std::string processName = "render_process_" + std::to_string(groupId);
        const char* binName = processName.c_str();
        char* argv[] = {const_cast<char*>(binName), NULL};
        if (execv("/system/bin/render_process", argv) == -1) {
            RS_LOGE("Fork execv command failed, errorno:%{public}d, errormsg:%{public}s", errno, strerror(errno));
            exit(-1);
        }
        return 0;
    } else {
        RS_LOGW("dmulti_process Forked success parent %{public}d, child %{public}d", getpid(), pid);
        return pid;
    }
}

void RSMultiRenderProcessManager::RecordRenderProcessConnection(pid_t pid, sptr<RSIServiceToRenderConnection> serviceToRenderConnection, sptr<RSIClientToRenderConnection> clientToRenderConnection)
{
    serviceToRenderConnections_[pid] = serviceToRenderConnection;
    clientToRenderConnections_[pid] = clientToRenderConnection;
}

pid_t RSMultiRenderProcessManager::GetRenderProcessPid(GroupId groupId)
{
    std::unique_lock<std::mutex> lock(mutex_);
    return groupIdToRenderProcessPid_[groupId];
}

sptr<RSScreenProperty> RSMultiRenderProcessManager::GetPendingScreenProperty(pid_t pid)
{
    if (auto it = pendingScreenConnectInfos_.find(pid); it != pendingScreenConnectInfos_.end()) {
        return it->second.property;
    }
    return nullptr;
}

std::promise<bool>& RSMultiRenderProcessManager::GetRenderProcessReadyPromise(pid_t pid)
{
    return renderProcessReadyPromises_[pid];
}

GroupId RSMultiRenderProcessManager::GetGroupId(ScreenId screenId)
{
    const auto& screenIdToGroupId = renderService_.renderModeConfig_->GetScreenIdToGroupId();
    const auto itr = screenIdToGroupId.find(screenId);
    const GroupId groupId = (itr != screenIdToGroupId.end()) ? itr->second : renderService_.renderModeConfig_->GetDefaultRenderProcess();
    return groupId;
}

sptr<IRemoteObject> RSMultiRenderProcessManager::OnScreenConnected(ScreenId id, const ScreenEventData& data, const RSScreenProperty& property)
{
    RSRenderProcessManager::OnScreenConnected(screenId, data, property);

    // 找到screenId对应groupId
    GroupId groupId = GetGroupId(screenId);
    sptr<IRemoteObject> renderConnProxy = groupIdToRenderProcessPid_.find(groupId) != groupIdToRenderProcessPid_.end() ?
        HandleExistGroup(groupId, screenId, proeprty);
        HandleNewGroup(groupId, screenId, proeprty);
    
    return renderConnProxy;
}

sptr<IRemoteObject> RSMultiRenderProcessManager::HandleExistGroup(GroupId groupId, ScreenId screenId, cosnt RSScreenProperty& property)
{
    RS_LOGI("dmulti_process groupId has connected already");
}

sptr<IRemoteObject> RSMultiRenderProcessManager::HandleNewGroup(GroupId groupId, ScreenId screenId, cosnt RSScreenProperty& property)
{
    RS_LOGI("dmulti_process groupId first time connect");
}

void RSMultiRenderProcessManager::OnScreenDisconnected(ScreenId id, const ScreenEventData& data)
{
    RSRenderProcessManager::OnScreenDisconnected(id, data);

    auto serviceToRenderConnection = GetServiceToRenderConn(id);
    if (serviceToRenderConnection == nullptr) {
        RS_LOGE("dmulti_process %{public}s: serviceToRenderConnection is nullptr", __func__);
        return;
    }
    serviceToRenderConnection->NotifyScreenDisconnectInfoToRender(id);
}

void RSMultiRenderProcessManager::OnScreenPropertyChanged(ScreenId id, const RSScreenProperty& property)
{
    RSRenderProcessManager::OnScreenPropertyChanged(id, property);

    auto serviceToRenderConnection = GetServiceToRenderConn(id);
    if (serviceToRenderConnection == nullptr) {
        RS_LOGE("dmulti_process %{public}s: serviceToRenderConnection is nullptr", __func__);
        return;
    }
    serviceToRenderConnection->NotifyScreenPropertyChangedInfoToRender(sptr<RSScreenProperty>::MakeSptr(property));
}

void RSMultiRenderProcessManager::OnFrameRefresh()
{
    // auto mainThread = RSMainThread::Instance();
    // if (mainThread == nullptr) {
    //     RS_LOGE("%{public}s: mainThread is nullptr", __func__);
    //     return;
    // }
    // mainThread->PostTask([mainThread]() {
    //     mainThread->SetForceUpdateUniRenderFlag(true);
    //     mainThread->RequestNextVSync();
    // });
    return;
}

void RSMultiRenderProcessManager::OnVBlankIdle(ScreenId id, uint64_t ns)
{
    // RSHardwareThread::Instance().PostTask([screenId, ns]() {
    //     RSHardwareThread::Instance().OnScreenVBlankIdleCallback(screenId, ns);
    // });
    return;
}

void RSMultiRenderProcessManager::OnVirtualScreenConnected(ScreenId id)
{
    return;
}

void RSMultiRenderProcessManager::OnVirtualScreenDisconnected(ScreenId id)
{
    return;
}

sptr<RSIServiceToRenderConnection> RSMultiRenderProcessManager::GetServiceToRenderConn(ScreenId screenId)
{
    GroupId groupId = GetGroupId(screenId);
    const auto pid = GetRenderProcessPid(groupId);
    auto it = serviceToRenderConnections_.find(pid);
    if (it != serviceToRenderConnections_.end()) {
        return it->second;
    }
    return nullptr;
}

std::vector<sptr<RSIServiceToRenderConnection>> RSMultiRenderProcessManager::GetServiceToRenderConns()
{
    std::vector<sptr<RSIServiceToRenderConnection>> connections;
    for (const auto& [_, conn] : serviceToRenderConnections_) {
        connections.emplace_back(conn);
    }
    return connections;
}

sptr<RSIClientToRenderConnection> RSMultiRenderProcessManager::GetClientToRenderConn(ScreenId screenId)
{
    GroupId groupId = GetGroupId(screenId);
    const auto pid = GetRenderProcessPid(groupId);
    auto it = clientToRenderConnections_.find(pid);
    if (it != clientToRenderConnections_.end()) {
        return it->second;
    }
    return nullptr;
}
} // namespace Rosen
} // namespace OHOS